"""
AI自动开发 - 执行服务层
负责命令执行、Python代码执行、长时间进程管理
"""

import os
from pathlib import Path
from datetime import datetime
from typing import Dict, Any
import platform
import asyncio

from utils import fix_encoding


class ExecutionService:
    """执行服务类"""

    def __init__(self):
        self.system = platform.system().lower()
        self.is_windows = self.system == 'windows'
        self.active_processes: Dict[str, Dict] = {}  # 活跃进程字典

        # 应用编码修复
        fix_encoding()

        # 危险命令黑名单
        self.dangerous_commands = [
            'format', 'del', 'rmdir', 'rd', 'deltree', 'fdisk',
            'shutdown', 'restart', 'reboot', 'net user', 'net localgroup',
            'reg delete', 'reg add', 'powershell', 'wmic', 'sc delete',
            'rm -rf', 'sudo rm', 'chmod 777'
        ]

    def _get_venv_paths(self, project_path: str) -> Dict[str, Path]:
        """获取虚拟环境相关路径"""
        project_dir = Path(project_path)
        venv_dir = project_dir / "venv"

        if self.is_windows:
            python_exe = venv_dir / "Scripts" / "python.exe"
            activate_script = venv_dir / "Scripts" / "activate.bat"
        else:
            python_exe = venv_dir / "bin" / "python"
            activate_script = venv_dir / "bin" / "activate"

        return {
            'venv_dir': venv_dir,
            'python_exe': python_exe,
            'activate_script': activate_script
        }

    def _is_command_safe(self, command: str) -> bool:
        """检查命令是否安全"""
        command_lower = command.lower()
        for dangerous in self.dangerous_commands:
            if dangerous in command_lower:
                return False
        return True

    def _prepare_environment(self, project_path: str) -> Dict[str, str]:
        """准备执行环境变量"""
        env = os.environ.copy()
        env['PYTHONIOENCODING'] = 'utf-8'
        env['PYTHONUNBUFFERED'] = '1'  # 实时输出

        # 设置虚拟环境路径
        paths = self._get_venv_paths(project_path)
        if paths['venv_dir'].exists():
            if self.is_windows:
                scripts_dir = str(paths['venv_dir'] / "Scripts")
                env['PATH'] = f"{scripts_dir};{env.get('PATH', '')}"
            else:
                bin_dir = str(paths['venv_dir'] / "bin")
                env['PATH'] = f"{bin_dir}:{env.get('PATH', '')}"

        return env

    def _wrap_command_for_venv(self, command: str, project_path: str) -> str:
        """将命令包装为在虚拟环境中执行"""
        paths = self._get_venv_paths(project_path)

        if not paths['venv_dir'].exists():
            return command  # 虚拟环境不存在，直接执行

        # 处理Python命令
        if command.startswith("python "):
            if paths['python_exe'].exists():
                return command.replace("python ", f'"{paths["python_exe"]}" ', 1)
        elif command.startswith("pip "):
            pip_exe = paths['venv_dir'] / ("Scripts/pip.exe" if self.is_windows else "bin/pip")
            if pip_exe.exists():
                return command.replace("pip ", f'"{pip_exe}" ', 1)

        return command

    def _log_execution(self, project_path: str, command: str, operation_type: str, summary: str = ""):
        """记录执行操作到项目日志"""
        try:
            from project_service import project_service
            log_summary = summary or f"执行{operation_type}: {command[:50]}..."
            project_service.log_file_change(project_path, 'execution', operation_type.upper(), log_summary)
        except Exception:
            pass

    # ===== 基础命令执行 =====

    async def execute_command(self, project_path: str, command: str, timeout: int = 30) -> Dict[str, Any]:
        """
        在虚拟环境中执行命令

        参数:
        - project_path: 项目路径
        - command: 要执行的命令
        - timeout: 超时时间（秒）

        返回:
        - dict: 执行结果
        """
        try:
            # 安全检查
            if not self._is_command_safe(command):
                return {
                    'success': False,
                    'message': f'禁止执行危险命令: {command}'
                }

            # 包装命令（虚拟环境）
            wrapped_command = self._wrap_command_for_venv(command, project_path)

            # 准备环境
            env = self._prepare_environment(project_path)

            # 执行命令
            process = await asyncio.create_subprocess_shell(
                wrapped_command,
                cwd=project_path,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
                env=env
            )

            try:
                stdout, stderr = await asyncio.wait_for(
                    process.communicate(),
                    timeout=timeout
                )
            except asyncio.TimeoutError:
                process.kill()
                await process.wait()
                return {
                    'success': False,
                    'message': f'命令执行超时 ({timeout}秒)',
                    'command': command,
                    'timeout': True
                }

            # 处理输出编码
            stdout_text = stdout.decode('utf-8', errors='replace') if stdout else ""
            stderr_text = stderr.decode('utf-8', errors='replace') if stderr else ""

            # 记录执行日志
            self._log_execution(project_path, command, 'COMMAND', f'执行命令: {command} - 返回码: {process.returncode}')

            return {
                'success': process.returncode == 0,
                'returncode': process.returncode,
                'command': command,
                'wrapped_command': wrapped_command,
                'stdout': stdout_text,
                'stderr': stderr_text,
                'execution_time': timeout,  # 实际执行时间可以后续优化
                'working_dir': str(Path(project_path).resolve())
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'命令执行失败: {str(e)}',
                'command': command
            }

    async def execute_python_code(self, project_path: str, code: str, timeout: int = 30) -> Dict[str, Any] | None:
        """
        执行Python代码（临时文件方式）

        参数:
        - project_path: 项目路径
        - code: Python代码
        - timeout: 超时时间（秒）

        返回:
        - dict: 执行结果
        """
        try:
            project_dir = Path(project_path)
            temp_file = project_dir / f"temp_script_{datetime.now().strftime('%H%M%S')}.py"

            # 写入临时文件
            temp_file.write_text(code, encoding='utf-8')

            try:
                # 构造执行命令
                command = f'python "{temp_file.name}"'

                # 执行代码
                result = await self.execute_command(project_path, command, timeout)

                # 添加额外信息
                result['code'] = code
                result['temp_file'] = str(temp_file)


                return result

            finally:
                # 清理临时文件
                try:
                    if temp_file.exists():
                        temp_file.unlink()
                except:
                    pass

        except Exception as e:
            return {
                'success': False,
                'message': f'Python代码执行失败: {str(e)}',
                'code': code
            }

    # ===== 长时间进程管理 =====

    async def start_long_process(self, project_path: str, command: str, process_name: str, output_file: str = None) -> \
    Dict[str, Any]:
        """
        启动长时间运行的进程

        参数:
        - project_path: 项目路径
        - command: 要执行的命令
        - process_name: 进程名称（用于管理）
        - output_file: 输出重定向文件（可选）

        返回:
        - dict: 启动结果
        """

        output_file_handle = None

        try:
            # 检查进程名是否已存在
            if process_name in self.active_processes:
                return {
                    'success': False,
                    'message': f'进程名 "{process_name}" 已存在'
                }

            # 安全检查
            if not self._is_command_safe(command):
                return {
                    'success': False,
                    'message': f'禁止执行危险命令: {command}'
                }

            # 包装命令
            wrapped_command = self._wrap_command_for_venv(command, project_path)

            # 准备环境
            env = self._prepare_environment(project_path)

            # 准备输出重定向
            output_file_handle = None
            if output_file:
                project_dir = Path(project_path)
                output_path = project_dir / output_file
                output_file_handle = open(output_path, 'w', encoding='utf-8')

            # 启动进程
            process = await asyncio.create_subprocess_shell(
                wrapped_command,
                cwd=project_path,
                stdout=output_file_handle or asyncio.subprocess.PIPE,
                stderr=output_file_handle,
                env=env
            )

            # 保存进程信息
            process_info = {
                'process': process,
                'start_time': datetime.now(),
                'command': command,
                'wrapped_command': wrapped_command,
                'output_file': output_file,
                'output_file_handle': output_file_handle,
                'project_path': project_path
            }

            self.active_processes[process_name] = process_info

            # 记录执行日志
            self._log_execution(project_path, command, 'START_PROCESS', f'启动长时间进程: {process_name}')

            return {
                'success': True,
                'message': f'进程 "{process_name}" 启动成功',
                'process_name': process_name,
                'pid': process.pid,
                'command': command,
                'output_file': output_file
            }

        except Exception as e:
            # 清理资源
            if output_file_handle:
                try:
                    output_file_handle.close()
                except:
                    pass

            return {
                'success': False,
                'message': f'启动进程失败: {str(e)}',
                'process_name': process_name
            }

    def terminate_process(self, process_name: str) -> Dict[str, Any]:
        """
        终止指定进程

        参数:
        - process_name: 进程名称

        返回:
        - dict: 终止结果
        """
        try:
            if process_name not in self.active_processes:
                return {
                    'success': False,
                    'message': f'进程 "{process_name}" 不存在'
                }

            process_info = self.active_processes[process_name]
            process = process_info['process']

            if process.returncode is None:  # 进程还在运行
                process.terminate()

                try:
                    # 使用asyncio等待进程退出（在同步函数中）


                    async def wait_with_timeout():
                        try:
                            await asyncio.wait_for(process.wait(), timeout=5.0)
                        except asyncio.TimeoutError:
                            process.kill()
                            await process.wait()

                    # 在同步函数中运行异步等待
                    loop = None
                    try:
                        loop = asyncio.get_event_loop()
                    except RuntimeError:
                        loop = asyncio.new_event_loop()
                        asyncio.set_event_loop(loop)

                    if loop.is_running():
                        # 如果事件循环正在运行，创建任务
                        asyncio.create_task(wait_with_timeout())
                    else:
                        # 如果事件循环未运行，直接运行
                        loop.run_until_complete(wait_with_timeout())

                except Exception:
                    # 如果异步等待失败，直接强制杀死
                    try:
                        process.kill()
                    except:
                        pass

            # 关闭文件句柄
            if 'output_file_handle' in process_info and process_info['output_file_handle']:
                try:
                    process_info['output_file_handle'].close()
                except:
                    pass

            # 计算运行时间
            run_time = datetime.now() - process_info['start_time']

            # 记录执行日志
            project_path = process_info.get('project_path', '')
            if project_path:
                self._log_execution(project_path, process_info['command'], 'TERMINATE_PROCESS',
                                    f'终止进程: {process_name}, 运行时间: {run_time}')

            # 从活跃进程列表中移除
            del self.active_processes[process_name]

            return {
                'success': True,
                'message': f'进程 "{process_name}" 已终止',
                'process_name': process_name,
                'run_time': str(run_time),
                'output_file': process_info.get('output_file')
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'终止进程失败: {str(e)}',
                'process_name': process_name
            }

    def list_active_processes(self) -> Dict[str, Any]:
        """
        列出所有活跃进程

        返回:
        - dict: 进程列表
        """
        try:
            if not self.active_processes:
                return {
                    'success': True,
                    'message': '当前没有活跃的进程',
                    'processes_count': 0,
                    'processes': []
                }

            processes = []
            for name, info in self.active_processes.items():
                process = info['process']
                start_time = info['start_time']
                run_time = datetime.now() - start_time

                # 检查进程状态
                if process.returncode is None:
                    status = 'running'
                    status_emoji = '🟢'
                else:
                    status = 'terminated'
                    status_emoji = '🔴'

                process_data = {
                    'name': name,
                    'pid': process.pid,
                    'status': status,
                    'status_emoji': status_emoji,
                    'returncode': process.returncode,
                    'command': info['command'],
                    'start_time': start_time.strftime('%H:%M:%S'),
                    'run_time': str(run_time),
                    'output_file': info.get('output_file'),
                    'project_path': info.get('project_path', '')
                }

                processes.append(process_data)

            return {
                'success': True,
                'processes_count': len(processes),
                'processes': processes
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'获取进程列表失败: {str(e)}'
            }

    def cleanup_zombie_processes(self) -> Dict[str, Any]:
        """
        清理僵尸进程

        返回:
        - dict: 清理结果
        """
        try:
            cleaned = []

            for name, info in list(self.active_processes.items()):
                process = info['process']

                if process.returncode is not None:  # 进程已经结束
                    # 关闭文件句柄
                    if 'output_file_handle' in info and info['output_file_handle']:
                        try:
                            info['output_file_handle'].close()
                        except:
                            pass

                    cleaned.append(name)
                    del self.active_processes[name]

            if cleaned:
                return {
                    'success': True,
                    'message': f'清理了 {len(cleaned)} 个僵尸进程',
                    'cleaned_processes': cleaned,
                    'cleaned_count': len(cleaned)
                }
            else:
                return {
                    'success': True,
                    'message': '没有发现僵尸进程',
                    'cleaned_count': 0
                }

        except Exception as e:
            return {
                'success': False,
                'message': f'清理僵尸进程失败: {str(e)}'
            }

    def read_process_output(self, project_path: str, output_file: str, last_lines: int = 10) -> Dict[str, Any]:
        """
        读取进程输出文件

        参数:
        - project_path: 项目路径
        - output_file: 输出文件名
        - last_lines: 读取最后N行（0表示全部）

        返回:
        - dict: 文件内容
        """
        try:
            project_dir = Path(project_path)
            file_path = project_dir / output_file

            if not file_path.exists():
                return {
                    'success': False,
                    'message': f'输出文件不存在: {output_file}'
                }

            content = file_path.read_text(encoding='utf-8')

            if last_lines > 0:
                lines = content.split('\n')
                if len(lines) > last_lines:
                    content = '\n'.join(lines[-last_lines:])
                    display_info = f'最后 {len(lines[-last_lines:])} 行'
                else:
                    display_info = '完整内容'
            else:
                display_info = '完整内容'

            return {
                'success': True,
                'output_file': output_file,
                'display_info': display_info,
                'content': content,
                'file_size': file_path.stat().st_size
            }

        except Exception as e:
            return {
                'success': False,
                'message': f'读取输出文件失败: {str(e)}',
                'output_file': output_file
            }


# 全局实例
execution_service = ExecutionService()

# 测试代码
if __name__ == "__main__":


    async def test_execution_service():
        test_project = "./test_project"

        print("执行服务测试:")

        # 测试基础命令执行
        result = await execution_service.execute_command(test_project, "python --version")
        print(f"Python版本: {result.get('stdout', '').strip()}")

        # 测试Python代码执行
        code = "print('Hello from execution service!')\nprint('Current time:', __import__('datetime').datetime.now())"
        result = await execution_service.execute_python_code(test_project, code)
        print(f"Python代码执行结果: {result['success']}")

        # 测试进程列表
        processes = execution_service.list_active_processes()
        print(f"活跃进程数: {processes['processes_count']}")


    # 运行测试
    asyncio.run(test_execution_service())